-
Notifications
You must be signed in to change notification settings - Fork 14.9k
[CIR] Upstream RTTI Builder & RTTI for VTable Definitions #160002
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[CIR] Upstream RTTI Builder & RTTI for VTable Definitions #160002
Conversation
@llvm/pr-subscribers-clang Author: Amr Hesham (AmrDeveloper) ChangesUpstream the RTTI builder with helpers and used them in the VTable Definitions Issue #154992 Patch is 79.34 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/160002.diff 9 Files Affected:
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
index 6a1746a7ad0ac..b76a15ded641b 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
@@ -89,6 +89,11 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
return cir::ConstRecordAttr::get(sTy, arrayAttr);
}
+ cir::TypeInfoAttr getTypeInfo(mlir::ArrayAttr fieldsAttr) {
+ auto anonRecord = getAnonConstRecord(fieldsAttr);
+ return cir::TypeInfoAttr::get(anonRecord.getType(), fieldsAttr);
+ }
+
std::string getUniqueAnonRecordName() { return getUniqueRecordName("anon"); }
std::string getUniqueRecordName(const std::string &baseName) {
diff --git a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
index ae922599809b8..1dee77425c30d 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
+++ b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
@@ -114,6 +114,9 @@ class CIRGenCXXABI {
virtual void emitRethrow(CIRGenFunction &cgf, bool isNoReturn) = 0;
+ virtual mlir::Attribute getAddrOfRTTIDescriptor(mlir::Location loc,
+ QualType ty) = 0;
+
/// Get the type of the implicit "this" parameter used by a method. May return
/// zero if no specific type is applicable, e.g. if the ABI expects the "this"
/// parameter to point to some artificial offset in a complete object due to
diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
index 0bf6cf556787c..3bf8dd34f3118 100644
--- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
@@ -103,6 +103,9 @@ class CIRGenItaniumCXXABI : public CIRGenCXXABI {
const CXXRecordDecl *rd) override;
void emitVirtualInheritanceTables(const CXXRecordDecl *rd) override;
+ mlir::Attribute getAddrOfRTTIDescriptor(mlir::Location loc,
+ QualType ty) override;
+
bool doStructorsInitializeVPtrs(const CXXRecordDecl *vtableClass) override {
return true;
}
@@ -111,6 +114,34 @@ class CIRGenItaniumCXXABI : public CIRGenCXXABI {
getVirtualBaseClassOffset(mlir::Location loc, CIRGenFunction &cgf,
Address thisAddr, const CXXRecordDecl *classDecl,
const CXXRecordDecl *baseClassDecl) override;
+
+ /**************************** RTTI Uniqueness ******************************/
+protected:
+ /// Returns true if the ABI requires RTTI type_info objects to be unique
+ /// across a program.
+ virtual bool shouldRTTIBeUnique() const { return true; }
+
+public:
+ /// What sort of unique-RTTI behavior should we use?
+ enum RTTIUniquenessKind {
+ /// We are guaranteeing, or need to guarantee, that the RTTI string
+ /// is unique.
+ RUK_Unique,
+
+ /// We are not guaranteeing uniqueness for the RTTI string, so we
+ /// can demote to hidden visibility but must use string comparisons.
+ RUK_NonUniqueHidden,
+
+ /// We are not guaranteeing uniqueness for the RTTI string, so we
+ /// have to use string comparisons, but we also have to emit it with
+ /// non-hidden visibility.
+ RUK_NonUniqueVisible
+ };
+
+ /// Return the required visibility status for the given type and linkage in
+ /// the current ABI.
+ RTTIUniquenessKind
+ classifyRTTIUniqueness(QualType canTy, cir::GlobalLinkageKind linkage) const;
};
} // namespace
@@ -424,6 +455,1006 @@ void CIRGenItaniumCXXABI::emitVirtualInheritanceTables(
vtables.emitVTTDefinition(vtt, cgm.getVTableLinkage(rd), rd);
}
+namespace {
+class CIRGenItaniumRTTIBuilder {
+ CIRGenModule &cgm; // Per-module state.
+ const CIRGenItaniumCXXABI &cxxABI; // Per-module state.
+
+ /// The fields of the RTTI descriptor currently being built.
+ SmallVector<mlir::Attribute, 16> fields;
+
+ // Returns the mangled type name of the given type.
+ cir::GlobalOp getAddrOfTypeName(mlir::Location loc, QualType ty,
+ cir::GlobalLinkageKind linkage);
+
+ /// descriptor of the given type.
+ mlir::Attribute getAddrOfExternalRTTIDescriptor(mlir::Location loc,
+ QualType ty);
+
+ /// Build the vtable pointer for the given type.
+ void buildVTablePointer(mlir::Location loc, const Type *ty);
+
+ /// Build an abi::__si_class_type_info, used for single inheritance, according
+ /// to the Itanium C++ ABI, 2.9.5p6b.
+ void buildSIClassTypeInfo(mlir::Location loc, const CXXRecordDecl *rd);
+
+ /// Build an abi::__vmi_class_type_info, used for
+ /// classes with bases that do not satisfy the abi::__si_class_type_info
+ /// constraints, according ti the Itanium C++ ABI, 2.9.5p5c.
+ void buildVMIClassTypeInfo(mlir::Location loc, const CXXRecordDecl *rd);
+
+public:
+ CIRGenItaniumRTTIBuilder(const CIRGenItaniumCXXABI &abi, CIRGenModule &_cgm)
+ : cgm(_cgm), cxxABI(abi) {}
+
+ /// Build the RTTI type info struct for the given type, or
+ /// link to an existing RTTI descriptor if one already exists.
+ mlir::Attribute buildTypeInfo(mlir::Location loc, QualType ty);
+
+ /// Build the RTTI type info struct for the given type.
+ mlir::Attribute buildTypeInfo(mlir::Location loc, QualType ty,
+ cir::GlobalLinkageKind linkage,
+ mlir::SymbolTable::Visibility visibility);
+};
+} // namespace
+
+// TODO(cir): Will be removed after sharing them with the classical codegen
+namespace {
+
+// Pointer type info flags.
+enum {
+ /// PTI_Const - Type has const qualifier.
+ PTI_Const = 0x1,
+
+ /// PTI_Volatile - Type has volatile qualifier.
+ PTI_Volatile = 0x2,
+
+ /// PTI_Restrict - Type has restrict qualifier.
+ PTI_Restrict = 0x4,
+
+ /// PTI_Incomplete - Type is incomplete.
+ PTI_Incomplete = 0x8,
+
+ /// PTI_ContainingClassIncomplete - Containing class is incomplete.
+ /// (in pointer to member).
+ PTI_ContainingClassIncomplete = 0x10,
+
+ /// PTI_TransactionSafe - Pointee is transaction_safe function (C++ TM TS).
+ // PTI_TransactionSafe = 0x20,
+
+ /// PTI_Noexcept - Pointee is noexcept function (C++1z).
+ PTI_Noexcept = 0x40,
+};
+
+// VMI type info flags.
+enum {
+ /// VMI_NonDiamondRepeat - Class has non-diamond repeated inheritance.
+ VMI_NonDiamondRepeat = 0x1,
+
+ /// VMI_DiamondShaped - Class is diamond shaped.
+ VMI_DiamondShaped = 0x2
+};
+
+// Base class type info flags.
+enum {
+ /// BCTI_Virtual - Base class is virtual.
+ BCTI_Virtual = 0x1,
+
+ /// BCTI_Public - Base class is public.
+ BCTI_Public = 0x2
+};
+
+/// Given a builtin type, returns whether the type
+/// info for that type is defined in the standard library.
+/// TODO(cir): this can unified with LLVM codegen
+static bool TypeInfoIsInStandardLibrary(const BuiltinType *ty) {
+ // Itanium C++ ABI 2.9.2:
+ // Basic type information (e.g. for "int", "bool", etc.) will be kept in
+ // the run-time support library. Specifically, the run-time support
+ // library should contain type_info objects for the types X, X* and
+ // X const*, for every X in: void, std::nullptr_t, bool, wchar_t, char,
+ // unsigned char, signed char, short, unsigned short, int, unsigned int,
+ // long, unsigned long, long long, unsigned long long, float, double,
+ // long double, char16_t, char32_t, and the IEEE 754r decimal and
+ // half-precision floating point types.
+ //
+ // GCC also emits RTTI for __int128.
+ // FIXME: We do not emit RTTI information for decimal types here.
+
+ // Types added here must also be added to EmitFundamentalRTTIDescriptors.
+ switch (ty->getKind()) {
+ case BuiltinType::WasmExternRef:
+ case BuiltinType::HLSLResource:
+ llvm_unreachable("NYI");
+ case BuiltinType::Void:
+ case BuiltinType::NullPtr:
+ case BuiltinType::Bool:
+ case BuiltinType::WChar_S:
+ case BuiltinType::WChar_U:
+ case BuiltinType::Char_U:
+ case BuiltinType::Char_S:
+ case BuiltinType::UChar:
+ case BuiltinType::SChar:
+ case BuiltinType::Short:
+ case BuiltinType::UShort:
+ case BuiltinType::Int:
+ case BuiltinType::UInt:
+ case BuiltinType::Long:
+ case BuiltinType::ULong:
+ case BuiltinType::LongLong:
+ case BuiltinType::ULongLong:
+ case BuiltinType::Half:
+ case BuiltinType::Float:
+ case BuiltinType::Double:
+ case BuiltinType::LongDouble:
+ case BuiltinType::Float16:
+ case BuiltinType::Float128:
+ case BuiltinType::Ibm128:
+ case BuiltinType::Char8:
+ case BuiltinType::Char16:
+ case BuiltinType::Char32:
+ case BuiltinType::Int128:
+ case BuiltinType::UInt128:
+ return true;
+
+#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
+ case BuiltinType::Id:
+#include "clang/Basic/OpenCLImageTypes.def"
+#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) case BuiltinType::Id:
+#include "clang/Basic/OpenCLExtensionTypes.def"
+ case BuiltinType::OCLSampler:
+ case BuiltinType::OCLEvent:
+ case BuiltinType::OCLClkEvent:
+ case BuiltinType::OCLQueue:
+ case BuiltinType::OCLReserveID:
+#define SVE_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
+#include "clang/Basic/AArch64ACLETypes.def"
+#define PPC_VECTOR_TYPE(Name, Id, Size) case BuiltinType::Id:
+#include "clang/Basic/PPCTypes.def"
+#define RVV_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
+#include "clang/Basic/RISCVVTypes.def"
+#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) case BuiltinType::Id:
+#include "clang/Basic/AMDGPUTypes.def"
+ case BuiltinType::ShortAccum:
+ case BuiltinType::Accum:
+ case BuiltinType::LongAccum:
+ case BuiltinType::UShortAccum:
+ case BuiltinType::UAccum:
+ case BuiltinType::ULongAccum:
+ case BuiltinType::ShortFract:
+ case BuiltinType::Fract:
+ case BuiltinType::LongFract:
+ case BuiltinType::UShortFract:
+ case BuiltinType::UFract:
+ case BuiltinType::ULongFract:
+ case BuiltinType::SatShortAccum:
+ case BuiltinType::SatAccum:
+ case BuiltinType::SatLongAccum:
+ case BuiltinType::SatUShortAccum:
+ case BuiltinType::SatUAccum:
+ case BuiltinType::SatULongAccum:
+ case BuiltinType::SatShortFract:
+ case BuiltinType::SatFract:
+ case BuiltinType::SatLongFract:
+ case BuiltinType::SatUShortFract:
+ case BuiltinType::SatUFract:
+ case BuiltinType::SatULongFract:
+ case BuiltinType::BFloat16:
+ return false;
+
+ case BuiltinType::Dependent:
+#define BUILTIN_TYPE(Id, SingletonId)
+#define PLACEHOLDER_TYPE(Id, SingletonId) case BuiltinType::Id:
+#include "clang/AST/BuiltinTypes.def"
+ llvm_unreachable("asking for RRTI for a placeholder type!");
+
+ case BuiltinType::ObjCId:
+ case BuiltinType::ObjCClass:
+ case BuiltinType::ObjCSel:
+ llvm_unreachable("FIXME: Objective-C types are unsupported!");
+ }
+
+ llvm_unreachable("Invalid BuiltinType Kind!");
+}
+
+static bool TypeInfoIsInStandardLibrary(const PointerType *pointerTy) {
+ QualType pointeeTy = pointerTy->getPointeeType();
+ const auto *builtinTy = dyn_cast<BuiltinType>(pointeeTy);
+ if (!builtinTy)
+ return false;
+
+ // Check the qualifiers.
+ Qualifiers quals = pointeeTy.getQualifiers();
+ quals.removeConst();
+
+ if (!quals.empty())
+ return false;
+
+ return TypeInfoIsInStandardLibrary(builtinTy);
+}
+
+/// IsStandardLibraryRTTIDescriptor - Returns whether the type
+/// information for the given type exists in the standard library.
+static bool IsStandardLibraryRTTIDescriptor(QualType ty) {
+ // Type info for builtin types is defined in the standard library.
+ if (const auto *builtinTy = dyn_cast<BuiltinType>(ty))
+ return TypeInfoIsInStandardLibrary(builtinTy);
+
+ // Type info for some pointer types to builtin types is defined in the
+ // standard library.
+ if (const auto *pointerTy = dyn_cast<PointerType>(ty))
+ return TypeInfoIsInStandardLibrary(pointerTy);
+
+ return false;
+}
+
+/// ShouldUseExternalRTTIDescriptor - Returns whether the type information for
+/// the given type exists somewhere else, and that we should not emit the type
+/// information in this translation unit. Assumes that it is not a
+/// standard-library type.
+static bool ShouldUseExternalRTTIDescriptor(CIRGenModule &cgm, QualType ty) {
+ ASTContext &context = cgm.getASTContext();
+
+ // If RTTI is disabled, assume it might be disabled in the
+ // translation unit that defines any potential key function, too.
+ if (!context.getLangOpts().RTTI)
+ return false;
+
+ if (const auto *recordTy = dyn_cast<RecordType>(ty)) {
+ const CXXRecordDecl *rd =
+ cast<CXXRecordDecl>(recordTy->getOriginalDecl())->getDefinitionOrSelf();
+ if (!rd->hasDefinition())
+ return false;
+
+ if (!rd->isDynamicClass())
+ return false;
+
+ // FIXME: this may need to be reconsidered if the key function
+ // changes.
+ // N.B. We must always emit the RTTI data ourselves if there exists a key
+ // function.
+ bool isDLLImport = rd->hasAttr<DLLImportAttr>();
+
+ // Don't import the RTTI but emit it locally.
+ if (cgm.getTriple().isOSCygMing())
+ return false;
+
+ if (cgm.getVTables().isVTableExternal(rd)) {
+ if (cgm.getTarget().hasPS4DLLImportExport())
+ return true;
+
+ return !isDLLImport || cgm.getTriple().isWindowsItaniumEnvironment();
+ }
+
+ if (isDLLImport)
+ return true;
+ }
+
+ return false;
+}
+
+/// Contains virtual and non-virtual bases seen when traversing a class
+/// hierarchy.
+struct SeenBases {
+ llvm::SmallPtrSet<const CXXRecordDecl *, 16> nonVirtualBases;
+ llvm::SmallPtrSet<const CXXRecordDecl *, 16> virtualBases;
+};
+
+/// Compute the value of the flags member in abi::__vmi_class_type_info.
+///
+static unsigned ComputeVMIClassTypeInfoFlags(const CXXBaseSpecifier *base,
+ SeenBases &bases) {
+
+ unsigned flags = 0;
+ auto *baseDecl = base->getType()->castAsCXXRecordDecl();
+
+ if (base->isVirtual()) {
+ // Mark the virtual base as seen.
+ if (!bases.virtualBases.insert(baseDecl).second) {
+ // If this virtual base has been seen before, then the class is diamond
+ // shaped.
+ flags |= VMI_DiamondShaped;
+ } else {
+ if (bases.nonVirtualBases.count(baseDecl))
+ flags |= VMI_NonDiamondRepeat;
+ }
+ } else {
+ // Mark the non-virtual base as seen.
+ if (!bases.nonVirtualBases.insert(baseDecl).second) {
+ // If this non-virtual base has been seen before, then the class has non-
+ // diamond shaped repeated inheritance.
+ flags |= VMI_NonDiamondRepeat;
+ } else {
+ if (bases.virtualBases.count(baseDecl))
+ flags |= VMI_NonDiamondRepeat;
+ }
+ }
+
+ // Walk all bases.
+ for (const auto &bs : baseDecl->bases())
+ flags |= ComputeVMIClassTypeInfoFlags(&bs, bases);
+
+ return flags;
+}
+
+static unsigned ComputeVMIClassTypeInfoFlags(const CXXRecordDecl *rd) {
+ unsigned flags = 0;
+ SeenBases bases;
+
+ // Walk all bases.
+ for (const auto &bs : rd->bases())
+ flags |= ComputeVMIClassTypeInfoFlags(&bs, bases);
+
+ return flags;
+}
+
+// Return whether the given record decl has a "single,
+// public, non-virtual base at offset zero (i.e. the derived class is dynamic
+// iff the base is)", according to Itanium C++ ABI, 2.95p6b.
+// TODO(cir): this can unified with LLVM codegen
+static bool CanUseSingleInheritance(const CXXRecordDecl *rd) {
+ // Check the number of bases.
+ if (rd->getNumBases() != 1)
+ return false;
+
+ // Get the base.
+ CXXRecordDecl::base_class_const_iterator base = rd->bases_begin();
+
+ // Check that the base is not virtual.
+ if (base->isVirtual())
+ return false;
+
+ // Check that the base is public.
+ if (base->getAccessSpecifier() != AS_public)
+ return false;
+
+ // Check that the class is dynamic iff the base is.
+ auto *baseDecl = base->getType()->castAsCXXRecordDecl();
+ return baseDecl->isEmpty() ||
+ baseDecl->isDynamicClass() == rd->isDynamicClass();
+}
+
+/// IsIncompleteClassType - Returns whether the given record type is incomplete.
+static bool IsIncompleteClassType(const RecordType *recordTy) {
+ return !recordTy->getOriginalDecl()
+ ->getDefinitionOrSelf()
+ ->isCompleteDefinition();
+}
+
+/// Returns whether the given type contains an
+/// incomplete class type. This is true if
+///
+/// * The given type is an incomplete class type.
+/// * The given type is a pointer type whose pointee type contains an
+/// incomplete class type.
+/// * The given type is a member pointer type whose class is an incomplete
+/// class type.
+/// * The given type is a member pointer type whoise pointee type contains an
+/// incomplete class type.
+/// is an indirect or direct pointer to an incomplete class type.
+static bool ContainsIncompleteClassType(QualType ty) {
+ if (const auto *recordTy = dyn_cast<RecordType>(ty)) {
+ if (IsIncompleteClassType(recordTy))
+ return true;
+ }
+
+ if (const auto *pointerTy = dyn_cast<PointerType>(ty))
+ return ContainsIncompleteClassType(pointerTy->getPointeeType());
+
+ if (const auto *memberPointerTy = dyn_cast<MemberPointerType>(ty)) {
+ // Check if the class type is incomplete.
+ if (!memberPointerTy->getMostRecentCXXRecordDecl()->hasDefinition())
+ return true;
+
+ return ContainsIncompleteClassType(memberPointerTy->getPointeeType());
+ }
+
+ return false;
+}
+
+/// Return the linkage that the type info and type info name constants
+/// should have for the given type.
+static cir::GlobalLinkageKind getTypeInfoLinkage(CIRGenModule &cgm,
+ QualType ty) {
+ // In addition, it and all of the intermediate abi::__pointer_type_info
+ // structs in the chain down to the abi::__class_type_info for the
+ // incomplete class type must be prevented from resolving to the
+ // corresponding type_info structs for the complete class type, possibly
+ // by making them local static objects. Finally, a dummy class RTTI is
+ // generated for the incomplete type that will not resolve to the final
+ // complete class RTTI (because the latter need not exist), possibly by
+ // making it a local static object.
+ if (ContainsIncompleteClassType(ty))
+ return cir::GlobalLinkageKind::InternalLinkage;
+
+ switch (ty->getLinkage()) {
+ case Linkage::Invalid:
+ llvm_unreachable("Linkage hasn't been computed!");
+
+ case Linkage::None:
+ case Linkage::Internal:
+ case Linkage::UniqueExternal:
+ return cir::GlobalLinkageKind::InternalLinkage;
+
+ case Linkage::VisibleNone:
+ case Linkage::Module:
+ case Linkage::External:
+ // RTTI is not enabled, which means that this type info struct is going
+ // to be used for exception handling. Give it linkonce_odr linkage.
+ if (!cgm.getLangOpts().RTTI)
+ return cir::GlobalLinkageKind::LinkOnceODRLinkage;
+
+ if (const RecordType *record = dyn_cast<RecordType>(ty)) {
+ const CXXRecordDecl *rd =
+ cast<CXXRecordDecl>(record->getOriginalDecl())->getDefinitionOrSelf();
+ if (rd->hasAttr<WeakAttr>())
+ return cir::GlobalLinkageKind::WeakODRLinkage;
+
+ if (cgm.getTriple().isWindowsItaniumEnvironment())
+ if (rd->hasAttr<DLLImportAttr>() &&
+ ShouldUseExternalRTTIDescriptor(cgm, ty))
+ return cir::GlobalLinkageKind::ExternalLinkage;
+
+ // MinGW always uses LinkOnceODRLinkage for type info.
+ if (rd->isDynamicClass() && !cgm.getASTContext()
+ .getTargetInfo()
+ .getTriple()
+ .isWindowsGNUEnvironment())
+ return cgm.getVTableLinkage(rd);
+ }
+
+ return cir::GlobalLinkageKind::LinkOnceODRLinkage;
+ }
+
+ llvm_unreachable("Invalid linkage!");
+}
+} // namespace
+
+// FIXME: Check please
+cir::GlobalOp
+CIRGenItaniumRTTIBuilder::getAddrOfTypeName(mlir::Location loc, QualType ty,
+ cir::GlobalLinkageKind linkage) {
+ auto &builder = cgm.getBuilder();
+ SmallString<256> name;
+ llvm::raw_svector_ostream out(name);
+ cgm.getCXXABI().getMangleContext().mangleCXXRTTIName(ty, out);
+
+ // We know that the mangled name of the type starts at index 4 of the
+ // mangled name of the typename, so we can just index into it in order to
+ // get the mangled name of the type.
+ mlir::Attribute init = builder.getString(
+ name.substr(4), ...
[truncated]
|
@llvm/pr-subscribers-clangir Author: Amr Hesham (AmrDeveloper) ChangesUpstream the RTTI builder with helpers and used them in the VTable Definitions Issue #154992 Patch is 79.34 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/160002.diff 9 Files Affected:
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuilder.h b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
index 6a1746a7ad0ac..b76a15ded641b 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuilder.h
+++ b/clang/lib/CIR/CodeGen/CIRGenBuilder.h
@@ -89,6 +89,11 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
return cir::ConstRecordAttr::get(sTy, arrayAttr);
}
+ cir::TypeInfoAttr getTypeInfo(mlir::ArrayAttr fieldsAttr) {
+ auto anonRecord = getAnonConstRecord(fieldsAttr);
+ return cir::TypeInfoAttr::get(anonRecord.getType(), fieldsAttr);
+ }
+
std::string getUniqueAnonRecordName() { return getUniqueRecordName("anon"); }
std::string getUniqueRecordName(const std::string &baseName) {
diff --git a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
index ae922599809b8..1dee77425c30d 100644
--- a/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
+++ b/clang/lib/CIR/CodeGen/CIRGenCXXABI.h
@@ -114,6 +114,9 @@ class CIRGenCXXABI {
virtual void emitRethrow(CIRGenFunction &cgf, bool isNoReturn) = 0;
+ virtual mlir::Attribute getAddrOfRTTIDescriptor(mlir::Location loc,
+ QualType ty) = 0;
+
/// Get the type of the implicit "this" parameter used by a method. May return
/// zero if no specific type is applicable, e.g. if the ABI expects the "this"
/// parameter to point to some artificial offset in a complete object due to
diff --git a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
index 0bf6cf556787c..3bf8dd34f3118 100644
--- a/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenItaniumCXXABI.cpp
@@ -103,6 +103,9 @@ class CIRGenItaniumCXXABI : public CIRGenCXXABI {
const CXXRecordDecl *rd) override;
void emitVirtualInheritanceTables(const CXXRecordDecl *rd) override;
+ mlir::Attribute getAddrOfRTTIDescriptor(mlir::Location loc,
+ QualType ty) override;
+
bool doStructorsInitializeVPtrs(const CXXRecordDecl *vtableClass) override {
return true;
}
@@ -111,6 +114,34 @@ class CIRGenItaniumCXXABI : public CIRGenCXXABI {
getVirtualBaseClassOffset(mlir::Location loc, CIRGenFunction &cgf,
Address thisAddr, const CXXRecordDecl *classDecl,
const CXXRecordDecl *baseClassDecl) override;
+
+ /**************************** RTTI Uniqueness ******************************/
+protected:
+ /// Returns true if the ABI requires RTTI type_info objects to be unique
+ /// across a program.
+ virtual bool shouldRTTIBeUnique() const { return true; }
+
+public:
+ /// What sort of unique-RTTI behavior should we use?
+ enum RTTIUniquenessKind {
+ /// We are guaranteeing, or need to guarantee, that the RTTI string
+ /// is unique.
+ RUK_Unique,
+
+ /// We are not guaranteeing uniqueness for the RTTI string, so we
+ /// can demote to hidden visibility but must use string comparisons.
+ RUK_NonUniqueHidden,
+
+ /// We are not guaranteeing uniqueness for the RTTI string, so we
+ /// have to use string comparisons, but we also have to emit it with
+ /// non-hidden visibility.
+ RUK_NonUniqueVisible
+ };
+
+ /// Return the required visibility status for the given type and linkage in
+ /// the current ABI.
+ RTTIUniquenessKind
+ classifyRTTIUniqueness(QualType canTy, cir::GlobalLinkageKind linkage) const;
};
} // namespace
@@ -424,6 +455,1006 @@ void CIRGenItaniumCXXABI::emitVirtualInheritanceTables(
vtables.emitVTTDefinition(vtt, cgm.getVTableLinkage(rd), rd);
}
+namespace {
+class CIRGenItaniumRTTIBuilder {
+ CIRGenModule &cgm; // Per-module state.
+ const CIRGenItaniumCXXABI &cxxABI; // Per-module state.
+
+ /// The fields of the RTTI descriptor currently being built.
+ SmallVector<mlir::Attribute, 16> fields;
+
+ // Returns the mangled type name of the given type.
+ cir::GlobalOp getAddrOfTypeName(mlir::Location loc, QualType ty,
+ cir::GlobalLinkageKind linkage);
+
+ /// descriptor of the given type.
+ mlir::Attribute getAddrOfExternalRTTIDescriptor(mlir::Location loc,
+ QualType ty);
+
+ /// Build the vtable pointer for the given type.
+ void buildVTablePointer(mlir::Location loc, const Type *ty);
+
+ /// Build an abi::__si_class_type_info, used for single inheritance, according
+ /// to the Itanium C++ ABI, 2.9.5p6b.
+ void buildSIClassTypeInfo(mlir::Location loc, const CXXRecordDecl *rd);
+
+ /// Build an abi::__vmi_class_type_info, used for
+ /// classes with bases that do not satisfy the abi::__si_class_type_info
+ /// constraints, according ti the Itanium C++ ABI, 2.9.5p5c.
+ void buildVMIClassTypeInfo(mlir::Location loc, const CXXRecordDecl *rd);
+
+public:
+ CIRGenItaniumRTTIBuilder(const CIRGenItaniumCXXABI &abi, CIRGenModule &_cgm)
+ : cgm(_cgm), cxxABI(abi) {}
+
+ /// Build the RTTI type info struct for the given type, or
+ /// link to an existing RTTI descriptor if one already exists.
+ mlir::Attribute buildTypeInfo(mlir::Location loc, QualType ty);
+
+ /// Build the RTTI type info struct for the given type.
+ mlir::Attribute buildTypeInfo(mlir::Location loc, QualType ty,
+ cir::GlobalLinkageKind linkage,
+ mlir::SymbolTable::Visibility visibility);
+};
+} // namespace
+
+// TODO(cir): Will be removed after sharing them with the classical codegen
+namespace {
+
+// Pointer type info flags.
+enum {
+ /// PTI_Const - Type has const qualifier.
+ PTI_Const = 0x1,
+
+ /// PTI_Volatile - Type has volatile qualifier.
+ PTI_Volatile = 0x2,
+
+ /// PTI_Restrict - Type has restrict qualifier.
+ PTI_Restrict = 0x4,
+
+ /// PTI_Incomplete - Type is incomplete.
+ PTI_Incomplete = 0x8,
+
+ /// PTI_ContainingClassIncomplete - Containing class is incomplete.
+ /// (in pointer to member).
+ PTI_ContainingClassIncomplete = 0x10,
+
+ /// PTI_TransactionSafe - Pointee is transaction_safe function (C++ TM TS).
+ // PTI_TransactionSafe = 0x20,
+
+ /// PTI_Noexcept - Pointee is noexcept function (C++1z).
+ PTI_Noexcept = 0x40,
+};
+
+// VMI type info flags.
+enum {
+ /// VMI_NonDiamondRepeat - Class has non-diamond repeated inheritance.
+ VMI_NonDiamondRepeat = 0x1,
+
+ /// VMI_DiamondShaped - Class is diamond shaped.
+ VMI_DiamondShaped = 0x2
+};
+
+// Base class type info flags.
+enum {
+ /// BCTI_Virtual - Base class is virtual.
+ BCTI_Virtual = 0x1,
+
+ /// BCTI_Public - Base class is public.
+ BCTI_Public = 0x2
+};
+
+/// Given a builtin type, returns whether the type
+/// info for that type is defined in the standard library.
+/// TODO(cir): this can unified with LLVM codegen
+static bool TypeInfoIsInStandardLibrary(const BuiltinType *ty) {
+ // Itanium C++ ABI 2.9.2:
+ // Basic type information (e.g. for "int", "bool", etc.) will be kept in
+ // the run-time support library. Specifically, the run-time support
+ // library should contain type_info objects for the types X, X* and
+ // X const*, for every X in: void, std::nullptr_t, bool, wchar_t, char,
+ // unsigned char, signed char, short, unsigned short, int, unsigned int,
+ // long, unsigned long, long long, unsigned long long, float, double,
+ // long double, char16_t, char32_t, and the IEEE 754r decimal and
+ // half-precision floating point types.
+ //
+ // GCC also emits RTTI for __int128.
+ // FIXME: We do not emit RTTI information for decimal types here.
+
+ // Types added here must also be added to EmitFundamentalRTTIDescriptors.
+ switch (ty->getKind()) {
+ case BuiltinType::WasmExternRef:
+ case BuiltinType::HLSLResource:
+ llvm_unreachable("NYI");
+ case BuiltinType::Void:
+ case BuiltinType::NullPtr:
+ case BuiltinType::Bool:
+ case BuiltinType::WChar_S:
+ case BuiltinType::WChar_U:
+ case BuiltinType::Char_U:
+ case BuiltinType::Char_S:
+ case BuiltinType::UChar:
+ case BuiltinType::SChar:
+ case BuiltinType::Short:
+ case BuiltinType::UShort:
+ case BuiltinType::Int:
+ case BuiltinType::UInt:
+ case BuiltinType::Long:
+ case BuiltinType::ULong:
+ case BuiltinType::LongLong:
+ case BuiltinType::ULongLong:
+ case BuiltinType::Half:
+ case BuiltinType::Float:
+ case BuiltinType::Double:
+ case BuiltinType::LongDouble:
+ case BuiltinType::Float16:
+ case BuiltinType::Float128:
+ case BuiltinType::Ibm128:
+ case BuiltinType::Char8:
+ case BuiltinType::Char16:
+ case BuiltinType::Char32:
+ case BuiltinType::Int128:
+ case BuiltinType::UInt128:
+ return true;
+
+#define IMAGE_TYPE(ImgType, Id, SingletonId, Access, Suffix) \
+ case BuiltinType::Id:
+#include "clang/Basic/OpenCLImageTypes.def"
+#define EXT_OPAQUE_TYPE(ExtType, Id, Ext) case BuiltinType::Id:
+#include "clang/Basic/OpenCLExtensionTypes.def"
+ case BuiltinType::OCLSampler:
+ case BuiltinType::OCLEvent:
+ case BuiltinType::OCLClkEvent:
+ case BuiltinType::OCLQueue:
+ case BuiltinType::OCLReserveID:
+#define SVE_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
+#include "clang/Basic/AArch64ACLETypes.def"
+#define PPC_VECTOR_TYPE(Name, Id, Size) case BuiltinType::Id:
+#include "clang/Basic/PPCTypes.def"
+#define RVV_TYPE(Name, Id, SingletonId) case BuiltinType::Id:
+#include "clang/Basic/RISCVVTypes.def"
+#define AMDGPU_TYPE(Name, Id, SingletonId, Width, Align) case BuiltinType::Id:
+#include "clang/Basic/AMDGPUTypes.def"
+ case BuiltinType::ShortAccum:
+ case BuiltinType::Accum:
+ case BuiltinType::LongAccum:
+ case BuiltinType::UShortAccum:
+ case BuiltinType::UAccum:
+ case BuiltinType::ULongAccum:
+ case BuiltinType::ShortFract:
+ case BuiltinType::Fract:
+ case BuiltinType::LongFract:
+ case BuiltinType::UShortFract:
+ case BuiltinType::UFract:
+ case BuiltinType::ULongFract:
+ case BuiltinType::SatShortAccum:
+ case BuiltinType::SatAccum:
+ case BuiltinType::SatLongAccum:
+ case BuiltinType::SatUShortAccum:
+ case BuiltinType::SatUAccum:
+ case BuiltinType::SatULongAccum:
+ case BuiltinType::SatShortFract:
+ case BuiltinType::SatFract:
+ case BuiltinType::SatLongFract:
+ case BuiltinType::SatUShortFract:
+ case BuiltinType::SatUFract:
+ case BuiltinType::SatULongFract:
+ case BuiltinType::BFloat16:
+ return false;
+
+ case BuiltinType::Dependent:
+#define BUILTIN_TYPE(Id, SingletonId)
+#define PLACEHOLDER_TYPE(Id, SingletonId) case BuiltinType::Id:
+#include "clang/AST/BuiltinTypes.def"
+ llvm_unreachable("asking for RRTI for a placeholder type!");
+
+ case BuiltinType::ObjCId:
+ case BuiltinType::ObjCClass:
+ case BuiltinType::ObjCSel:
+ llvm_unreachable("FIXME: Objective-C types are unsupported!");
+ }
+
+ llvm_unreachable("Invalid BuiltinType Kind!");
+}
+
+static bool TypeInfoIsInStandardLibrary(const PointerType *pointerTy) {
+ QualType pointeeTy = pointerTy->getPointeeType();
+ const auto *builtinTy = dyn_cast<BuiltinType>(pointeeTy);
+ if (!builtinTy)
+ return false;
+
+ // Check the qualifiers.
+ Qualifiers quals = pointeeTy.getQualifiers();
+ quals.removeConst();
+
+ if (!quals.empty())
+ return false;
+
+ return TypeInfoIsInStandardLibrary(builtinTy);
+}
+
+/// IsStandardLibraryRTTIDescriptor - Returns whether the type
+/// information for the given type exists in the standard library.
+static bool IsStandardLibraryRTTIDescriptor(QualType ty) {
+ // Type info for builtin types is defined in the standard library.
+ if (const auto *builtinTy = dyn_cast<BuiltinType>(ty))
+ return TypeInfoIsInStandardLibrary(builtinTy);
+
+ // Type info for some pointer types to builtin types is defined in the
+ // standard library.
+ if (const auto *pointerTy = dyn_cast<PointerType>(ty))
+ return TypeInfoIsInStandardLibrary(pointerTy);
+
+ return false;
+}
+
+/// ShouldUseExternalRTTIDescriptor - Returns whether the type information for
+/// the given type exists somewhere else, and that we should not emit the type
+/// information in this translation unit. Assumes that it is not a
+/// standard-library type.
+static bool ShouldUseExternalRTTIDescriptor(CIRGenModule &cgm, QualType ty) {
+ ASTContext &context = cgm.getASTContext();
+
+ // If RTTI is disabled, assume it might be disabled in the
+ // translation unit that defines any potential key function, too.
+ if (!context.getLangOpts().RTTI)
+ return false;
+
+ if (const auto *recordTy = dyn_cast<RecordType>(ty)) {
+ const CXXRecordDecl *rd =
+ cast<CXXRecordDecl>(recordTy->getOriginalDecl())->getDefinitionOrSelf();
+ if (!rd->hasDefinition())
+ return false;
+
+ if (!rd->isDynamicClass())
+ return false;
+
+ // FIXME: this may need to be reconsidered if the key function
+ // changes.
+ // N.B. We must always emit the RTTI data ourselves if there exists a key
+ // function.
+ bool isDLLImport = rd->hasAttr<DLLImportAttr>();
+
+ // Don't import the RTTI but emit it locally.
+ if (cgm.getTriple().isOSCygMing())
+ return false;
+
+ if (cgm.getVTables().isVTableExternal(rd)) {
+ if (cgm.getTarget().hasPS4DLLImportExport())
+ return true;
+
+ return !isDLLImport || cgm.getTriple().isWindowsItaniumEnvironment();
+ }
+
+ if (isDLLImport)
+ return true;
+ }
+
+ return false;
+}
+
+/// Contains virtual and non-virtual bases seen when traversing a class
+/// hierarchy.
+struct SeenBases {
+ llvm::SmallPtrSet<const CXXRecordDecl *, 16> nonVirtualBases;
+ llvm::SmallPtrSet<const CXXRecordDecl *, 16> virtualBases;
+};
+
+/// Compute the value of the flags member in abi::__vmi_class_type_info.
+///
+static unsigned ComputeVMIClassTypeInfoFlags(const CXXBaseSpecifier *base,
+ SeenBases &bases) {
+
+ unsigned flags = 0;
+ auto *baseDecl = base->getType()->castAsCXXRecordDecl();
+
+ if (base->isVirtual()) {
+ // Mark the virtual base as seen.
+ if (!bases.virtualBases.insert(baseDecl).second) {
+ // If this virtual base has been seen before, then the class is diamond
+ // shaped.
+ flags |= VMI_DiamondShaped;
+ } else {
+ if (bases.nonVirtualBases.count(baseDecl))
+ flags |= VMI_NonDiamondRepeat;
+ }
+ } else {
+ // Mark the non-virtual base as seen.
+ if (!bases.nonVirtualBases.insert(baseDecl).second) {
+ // If this non-virtual base has been seen before, then the class has non-
+ // diamond shaped repeated inheritance.
+ flags |= VMI_NonDiamondRepeat;
+ } else {
+ if (bases.virtualBases.count(baseDecl))
+ flags |= VMI_NonDiamondRepeat;
+ }
+ }
+
+ // Walk all bases.
+ for (const auto &bs : baseDecl->bases())
+ flags |= ComputeVMIClassTypeInfoFlags(&bs, bases);
+
+ return flags;
+}
+
+static unsigned ComputeVMIClassTypeInfoFlags(const CXXRecordDecl *rd) {
+ unsigned flags = 0;
+ SeenBases bases;
+
+ // Walk all bases.
+ for (const auto &bs : rd->bases())
+ flags |= ComputeVMIClassTypeInfoFlags(&bs, bases);
+
+ return flags;
+}
+
+// Return whether the given record decl has a "single,
+// public, non-virtual base at offset zero (i.e. the derived class is dynamic
+// iff the base is)", according to Itanium C++ ABI, 2.95p6b.
+// TODO(cir): this can unified with LLVM codegen
+static bool CanUseSingleInheritance(const CXXRecordDecl *rd) {
+ // Check the number of bases.
+ if (rd->getNumBases() != 1)
+ return false;
+
+ // Get the base.
+ CXXRecordDecl::base_class_const_iterator base = rd->bases_begin();
+
+ // Check that the base is not virtual.
+ if (base->isVirtual())
+ return false;
+
+ // Check that the base is public.
+ if (base->getAccessSpecifier() != AS_public)
+ return false;
+
+ // Check that the class is dynamic iff the base is.
+ auto *baseDecl = base->getType()->castAsCXXRecordDecl();
+ return baseDecl->isEmpty() ||
+ baseDecl->isDynamicClass() == rd->isDynamicClass();
+}
+
+/// IsIncompleteClassType - Returns whether the given record type is incomplete.
+static bool IsIncompleteClassType(const RecordType *recordTy) {
+ return !recordTy->getOriginalDecl()
+ ->getDefinitionOrSelf()
+ ->isCompleteDefinition();
+}
+
+/// Returns whether the given type contains an
+/// incomplete class type. This is true if
+///
+/// * The given type is an incomplete class type.
+/// * The given type is a pointer type whose pointee type contains an
+/// incomplete class type.
+/// * The given type is a member pointer type whose class is an incomplete
+/// class type.
+/// * The given type is a member pointer type whoise pointee type contains an
+/// incomplete class type.
+/// is an indirect or direct pointer to an incomplete class type.
+static bool ContainsIncompleteClassType(QualType ty) {
+ if (const auto *recordTy = dyn_cast<RecordType>(ty)) {
+ if (IsIncompleteClassType(recordTy))
+ return true;
+ }
+
+ if (const auto *pointerTy = dyn_cast<PointerType>(ty))
+ return ContainsIncompleteClassType(pointerTy->getPointeeType());
+
+ if (const auto *memberPointerTy = dyn_cast<MemberPointerType>(ty)) {
+ // Check if the class type is incomplete.
+ if (!memberPointerTy->getMostRecentCXXRecordDecl()->hasDefinition())
+ return true;
+
+ return ContainsIncompleteClassType(memberPointerTy->getPointeeType());
+ }
+
+ return false;
+}
+
+/// Return the linkage that the type info and type info name constants
+/// should have for the given type.
+static cir::GlobalLinkageKind getTypeInfoLinkage(CIRGenModule &cgm,
+ QualType ty) {
+ // In addition, it and all of the intermediate abi::__pointer_type_info
+ // structs in the chain down to the abi::__class_type_info for the
+ // incomplete class type must be prevented from resolving to the
+ // corresponding type_info structs for the complete class type, possibly
+ // by making them local static objects. Finally, a dummy class RTTI is
+ // generated for the incomplete type that will not resolve to the final
+ // complete class RTTI (because the latter need not exist), possibly by
+ // making it a local static object.
+ if (ContainsIncompleteClassType(ty))
+ return cir::GlobalLinkageKind::InternalLinkage;
+
+ switch (ty->getLinkage()) {
+ case Linkage::Invalid:
+ llvm_unreachable("Linkage hasn't been computed!");
+
+ case Linkage::None:
+ case Linkage::Internal:
+ case Linkage::UniqueExternal:
+ return cir::GlobalLinkageKind::InternalLinkage;
+
+ case Linkage::VisibleNone:
+ case Linkage::Module:
+ case Linkage::External:
+ // RTTI is not enabled, which means that this type info struct is going
+ // to be used for exception handling. Give it linkonce_odr linkage.
+ if (!cgm.getLangOpts().RTTI)
+ return cir::GlobalLinkageKind::LinkOnceODRLinkage;
+
+ if (const RecordType *record = dyn_cast<RecordType>(ty)) {
+ const CXXRecordDecl *rd =
+ cast<CXXRecordDecl>(record->getOriginalDecl())->getDefinitionOrSelf();
+ if (rd->hasAttr<WeakAttr>())
+ return cir::GlobalLinkageKind::WeakODRLinkage;
+
+ if (cgm.getTriple().isWindowsItaniumEnvironment())
+ if (rd->hasAttr<DLLImportAttr>() &&
+ ShouldUseExternalRTTIDescriptor(cgm, ty))
+ return cir::GlobalLinkageKind::ExternalLinkage;
+
+ // MinGW always uses LinkOnceODRLinkage for type info.
+ if (rd->isDynamicClass() && !cgm.getASTContext()
+ .getTargetInfo()
+ .getTriple()
+ .isWindowsGNUEnvironment())
+ return cgm.getVTableLinkage(rd);
+ }
+
+ return cir::GlobalLinkageKind::LinkOnceODRLinkage;
+ }
+
+ llvm_unreachable("Invalid linkage!");
+}
+} // namespace
+
+// FIXME: Check please
+cir::GlobalOp
+CIRGenItaniumRTTIBuilder::getAddrOfTypeName(mlir::Location loc, QualType ty,
+ cir::GlobalLinkageKind linkage) {
+ auto &builder = cgm.getBuilder();
+ SmallString<256> name;
+ llvm::raw_svector_ostream out(name);
+ cgm.getCXXABI().getMangleContext().mangleCXXRTTIName(ty, out);
+
+ // We know that the mangled name of the type starts at index 4 of the
+ // mangled name of the typename, so we can just index into it in order to
+ // get the mangled name of the type.
+ mlir::Attribute init = builder.getString(
+ name.substr(4), ...
[truncated]
|
Notes:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is an awful lot of code, and a lot of it isn't covered by the test. Is it possible to strip this down to just the paths that are needed by the test and replace the rest with NYI markers?
Also, throughout this PR there are a lot of places where our usual naming conventions aren't being followed, auto is overused, and llvm_unreachable is used where errorNYI should be. I marker some of them, but not all.
87e9469
to
3dfa20a
Compare
I am still working on merging the tests, and i addressed other comments |
I added checks for RTTI in VTT |
auto &builder = cgm.getBuilder(); | ||
|
||
// abi::__class_type_info. | ||
static const char *const ClassTypeInfo = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's unclear to me what you're intending to do here. This is part of the code that you're trying to move into a shared location, right? Do you want to commit this implementation here and remove it later if/when the shared code refactoring is accepted?
What I was saying is that if this is going to be committed into CIR/CodeGen
it should follow the naming conventions there. For example, vtableClassNameForType
and classTypeInfo
.
My idea was to isolate the shared part into an anonymous namespace, and once #157936 is accepted and merged, I will just remove that namespace, and everything should work fine. I totally agree that anything that will be committed to CIR/** should follow the name conventions that we use. However, the downside is that we will need to refactor twice to make the shared code have the same style as CIR/* and then revert function names once the refector PR is merged. I am totally okay with that, it will not be too many changes (Less than maybe adding temp CGM :D), I will do that now. |
5d92c95
to
09aeed8
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this got trimmed down significantly, lot of NYI skeleton and a few actual changes, which seem all to be tested, so LGTM. Andy has been more involved here so I'd wait until he stamps this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm happy with this now. Thanks for your diligence in seeing this through.
static bool opGlobalDLLImportExport() { return false; } | ||
static bool opGlobalPartition() { return false; } | ||
static bool opGlobalUsedOrCompilerUsed() { return false; } | ||
static bool setDSOLocal() { return false; } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We support both dso_local and comdat on globals now, but I think it's fine to defer that handling until after this PR is merged.
case Type::ArrayParameter: | ||
case Type::HLSLAttributedResource: | ||
case Type::HLSLInlineSpirv: | ||
llvm_unreachable("NYI"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
errorNYI
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For HLSLAttributedResource
and HLSLInlineSpirv
, they are not supported HLSL doesn't support RTTI
so i made them llvm_unreachable
similar to OGCG and for ArrayParameter
i moved it into the correct section, now we have the same order as classical codegen
Upstream the RTTI builder with helpers and used them in the VTable Definitions Issue llvm#154992
Upstream the RTTI builder with helpers and used them in the VTable Definitions
Issue #154992